package com.xuexiang.xuidemo.refresh;

import ohos.agp.components.VelocityDetector;
import ohos.multimodalinput.event.TouchEvent;
import com.xuexiang.xuidemo.view.ComponentConfiguration;


/**
 * 手势识别器
 *
 * @author 裴云飞
 * @since 2020-12-27
 */
public class GestureDetector {
    /**
     * 手势识别器
     *
     * @author 裴云飞
     * @since 2021-03-27
     */
    public interface OnGestureListener {
        /**
         * 发生滚动时回调
         *
         * @param e1 手指按下时的事件
         * @param e2 手指移动时的事件
         * @param distanceX 横向的移动距离
         * @param distanceY 纵向的移动距离
         * @return 1
         */
        boolean onScroll(TouchEvent e1, TouchEvent e2, float distanceX, float distanceY);
    }

    private int mTouchSlopSquare;
    private final OnGestureListener mListener;
    private boolean isAlwaysInTapRegion;
    private TouchEvent mCurrentDownEvent;
//    private TouchEvent mCurrentMotionEvent;
//    private TouchEvent mPreviousUpEvent;
    private float mLastFocusX;
    private float mLastFocusY;
    private float mDownFocusX;
    private float mDownFocusY;
    private VelocityDetector mVelocityTracker;

    /**
     * 手势监听
     *
     * @param listener
     */
    public GestureDetector(OnGestureListener listener) {
        mListener = listener;
        int touchSlop = ComponentConfiguration.getScaledTouchSlop();

        // 滑动的时候，手指的移动要大于这个距离才算发生了滚动
        mTouchSlopSquare = touchSlop * touchSlop;
    }

    /**
     * 触摸监听
     *
     * @param ev
     * @return false
     */
    public boolean onTouchEvent(TouchEvent ev) {
        final int action = ev.getAction();
        doadd(ev);
        final int ab = -1;
        final boolean pointerUp = action == TouchEvent.OTHER_POINT_UP;
        final int skipIndex = pointerUp ? ev.getIndex() : ab;

        final int count = ev.getPointerCount();

        // 把所有还在触摸的手指的位置x，y加起来，后面求平均数，算出中心焦点
        float sumX = 0;
        float sumY = 0;

        for (int aj = 0; aj < count; aj++) {
            if (skipIndex == aj) {
                // 跳过非主要指针的抬起动作
                continue;
            }
            sumX += ev.getPointerPosition(aj).getX();
            sumY += ev.getPointerPosition(aj).getY();
        }
        final int div = pointerUp ? count - 1 : count;

        // 求平均值，算出中心焦点
        final float focusX = sumX / div;
        final float focusY = sumY / div;
        boolean handled = false;
        switch (action) {
            case TouchEvent.OTHER_POINT_DOWN:
            case TouchEvent.OTHER_POINT_UP:
                doaction(focusX, focusY);
                break;
            case TouchEvent.PRIMARY_POINT_DOWN:
                doaction(focusX, focusY);
                doset(ev);
                break;
            case TouchEvent.POINT_MOVE:
                final float scrollX = mLastFocusX - focusX;
                final float scrollY = mLastFocusY - focusY;
                if (isAlwaysInTapRegion) {
                    final int deltaX = (int) (focusX - mDownFocusX);
                    final int deltaY = (int) (focusY - mDownFocusY);
                    int distance = (deltaX * deltaX) + (deltaY * deltaY);
                    int slopSquare = mTouchSlopSquare;

                    if (distance > slopSquare) {
                        handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                        domoveset(focusX,focusY);
                    }
                } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
                    handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                    domoveelseset(focusX,focusY);
                }
                break;
            default:
        }
        return handled;
    }

    private void domoveelseset(float focusX, float focusY) {
        mLastFocusX = focusX;
        mLastFocusY = focusY;
    }

    private void domoveset(float focusX, float focusY) {
        mLastFocusX = focusX;
        mLastFocusY = focusY;
        isAlwaysInTapRegion = false;
    }

    private void doset(TouchEvent ev) {
        mCurrentDownEvent = ev;
        isAlwaysInTapRegion = true;
    }

    private void doaction(float focusX, float focusY) {
        mDownFocusX = focusX;
        mLastFocusX = focusX;
        mDownFocusY = focusY;
        mLastFocusY = focusY;
    }

    private void doadd(TouchEvent ev) {
//        mCurrentMotionEvent = ev;
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityDetector.obtainInstance();
        }
        mVelocityTracker.addEvent(ev);
    }
}